package jzbank.job;

import jzbank.config.OConnManagerment;
import jzbank.dao.serializabledao.DataExportDao;
import jzbank.dao.serializabledao.impl.DataExportDaoImpl;
import jzbank.pojo.dto.DataExportDTO;
import jzbank.util.*;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import java.io.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @auther admin闫
 * @Descriptopn
 * @date 2023/9/25 21:29
 */
@Slf4j
public class DataExportJob implements Job {


    DataExportDao dataExportDao=new DataExportDaoImpl();

    // 使用Runtime来执行command，生成一个Process对像
//    // 初始化读取配置文件到内存
//    private static ConfigReader cfgrd = new ConfigReader(System.getProperty("user.dir") + "/config/config.properties");

    /**
     * 文件推送定时任务
     * @param jobExecutionContext
     * @throws JobExecutionException
     */
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        String taskName = jobDetail.getKey().getName();
        //获取任务参数
        DataExportDTO dataExport = dataExportDao.getDataExportByName(taskName);
//        System.out.println(dataExport.toString());
        log.info("任务正式开始执行："+dataExport.toString());
//        startExport();
        // 获取当前时间
        Date currentTime = new Date();
        // 创建格式化器
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        // 格式化并输出时间
        String formattedTime = sdf.format(currentTime);
        log.info("当前开始--------当前时间：" + formattedTime);

        // 从 dataExport 对象中获取参数
        String tId = dataExport.getTid();
        String dbIp = dataExport.getDbIp();
        String dbUserName = dataExport.getDbUserName();
        String dbPassWord = dataExport.getDbPassWord();
        String dataExportPathpar = dataExport.getDataExportPath();
        String dataFileKeepTime = dataExport.getDataFileKeepTime();
        String dbClientName = dataExport.getDbClientName();
        String SysNum = dataExport.getSysNum();
        String exportShell = dataExport.getExportShell();
        String isCreateCtl = dataExport.getIsCreateCtl();
        String tableName = dataExport.getTableName();
        String tableIsIncrements = dataExport.getTableIsIncrements();
        String isEnableFtp = dataExport.getIsEnableFtp();
        String ftpPath = dataExport.getFtpPath();
        String ftpIp = dataExport.getFtpIp();
        String ftpUserName = dataExport.getFtpUserName();
        String ftpPassword = dataExport.getFtpPassword();
        String ftpPort = dataExport.getFtpPort();

        String tableIsIncrementsSQL = dataExport.getTableIsIncrementsSQL();

        // 调用 startExport 方法
        startExport(tId, dbIp, dbUserName, dbPassWord, dataExportPathpar, dataFileKeepTime,
                dbClientName, SysNum, exportShell, isCreateCtl, tableName, tableIsIncrements,
                isEnableFtp, ftpPath, ftpIp, ftpUserName, ftpPassword, ftpPort, tableIsIncrementsSQL);


        // 获取当前时间
        Date endTime = new Date();
        // 创建格式化器
        SimpleDateFormat end = new SimpleDateFormat("HH:mm:ss");
        // 格式化并输出时间
        String s = end.format(endTime);
        log.info("执行结束-------现在时间：" + s);



    }

    /**
     * 数据平台推送任务
     * @param dbIp 数据库服务器 ip
     * @param dbUserName 数据库用户名
     * @param dbPassWord 数据库密码
     * @param dataExportPathpar 数据文件导出路径
     * @param dataFileKeepTime 数据导出文件保留时间 (毫秒)
     * @param dbClientName 数据库实例名
     * @param SysNum 系统编码
     * @param exportShell 导出命令（SQL）
     * @param isCreateCtl 是否生成ctl文件
     * @param tableName 表名
     * @param tableIsIncrements 0全量导出/1 增量导出/2先全量导出后曾量导出
     * @param isEnableFtp 是否FTP传输
     * @param ftpPath Ftp路径
     * @param ftpIp FtpIP地址
     * @param ftpUserName FTP用户名
     * @param ftpPassword FTP密码
     * @param ftpPort FTP端口
     * @param tableIsIncrementsSQL 增量导出SQL
     */
    public void startExport(
            String tId,
            String dbIp,String dbUserName,String dbPassWord,
            String dataExportPathpar,String dataFileKeepTime,
            String dbClientName,String SysNum,String exportShell,
            String isCreateCtl,String tableName, String tableIsIncrements,
            String isEnableFtp,String ftpPath,String ftpIp,
            String ftpUserName,String ftpPassword,String ftpPort,
            String tableIsIncrementsSQL
    ) {

        RemoteShellExecutor executor = new RemoteShellExecutor(dbIp, dbUserName,
                dbPassWord);
        try {
            File dataExportPath = new File(dataExportPathpar);
            createLinuxPath(dataExportPathpar,executor);
            //链接数据库
            int ret = executor.sh("db2 connect to " + dbClientName + " user " + dbUserName
                    + " using " + dbPassWord);

            if (0 == ret) {
                log.info("链接数据库成功!!!");
            } else {
                log.info("链接数据库失败!!!");
                return;
            }
            // 准备日期 和时间参数
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            long yesteday = new Date().getTime() - 86400000;// 一天有 86400000 毫秒
            Date today = new Date();
            today.setTime(yesteday);
            // 日期
            String day = sdf.format(today);
            // 当天导出文件存放路径
            File dayPath = new File(dataExportPathpar + "/" + day);
            createLinuxPath(dataExportPathpar + "/" + day,executor);
//            if (!dayPath.exists()) {
//                dayPath.mkdirs();
//                log.info("生成路径" + dayPath.getAbsolutePath() + "!!!");
//            }
            // 导出数据文件
            log.info("导出柜员信息表数据开始!!!");
            // 表导出文件路径
            String DataPath = dayPath + File.separator + SysNum + "_"+tableName+".dat";
            DataPath = DataPath.replace("\\", "/");
            // 0 全量 1 增量 -1首次全量以后增量
            if(tableIsIncrements.equals("0")) {
                // 0 全量
                log.info("全量导出"+tableName);
                exportShell = "db2 \"export to " + DataPath + " of del "
                        + "MODIFIED BY CODEPAGE = 1208 NOCHARDEL COLDEL0x1b DECPLUSBLANK STRIPLZEROS "
                        + exportShell +"\"";
            }else if(tableIsIncrements.equals("1")) {
                //1 增量
                log.info("增量导出"+tableName);
                exportShell = "db2 \"export to " + DataPath + " of del "
                        + "MODIFIED BY CODEPAGE = 1208 NOCHARDEL COLDEL0x1b DECPLUSBLANK STRIPLZEROS "
                        + exportShell+" " + tableIsIncrementsSQL +"\"";
            }else if (tableIsIncrements.equals("-1")){
                //-1 首次全量 以后增量
                setTaskToIncrements(tId);// 修改为增量
                //1 增量
                log.info("首次全量导出"+tableName);
                exportShell = "db2 \"export to " + DataPath + " of del "
                        + "MODIFIED BY CODEPAGE = 1208 NOCHARDEL COLDEL0x1b DECPLUSBLANK STRIPLZEROS "
                        + exportShell+"\"";
            }

            log.info("导出shell"+ exportShell);

            //执行SQL
            int ExportRet = executor.sh(exportShell);
            //Ctl 文件路径
            String CtlPath = "";
            //导出是否成功
            if (0 == ExportRet) {
                log.info("导出"+tableName+"信息表数据成功!!!");
                // 柜员信息表就绪文件路径
                //ctl文件生成  是否导出Ctl 文件  1导出 0 不导出
//                if (isCreateCtl.equals("1")){
                if (false){
                    CtlPath = createCtlFile(DataPath, day, getDataCount("select count(1) from CLERKTABLE"),SysNum);
                    if (CtlPath != null) {
                        log.info(tableName+"就绪文件生成成功!!!");
                    } else {
                        log.info(tableName+"就绪文件生成失败!!!");
                    }
                }else {
                    log.info("无需生成"+tableName+"信息表就绪文件!!!");
                }
            } else {
                log.info("导出"+tableName+"数据失败!!!");
                return;
            }
            //是否FTP传输   0传输 1不传输
            if (isEnableFtp.equals("0")) {
                // FTP传输文件
                InputStream input = null;
                String filename = "";
                String datFtpPath = ftpPath + "/" + day;
                //上传准备
                filename = SysNum + "_"+tableName+".dat";
                input = new FileInputStream(new File(DataPath));
                if (FtpUtil.uploadFile(ftpIp, ftpUserName, ftpPassword,
                        Integer.valueOf(ftpPort), datFtpPath, filename, input)) {
                    log.info("柜员信息表数据推送成功!!!");
                    // 柜员信息表就绪文件
                    filename = SysNum + "_"+tableName+".ctl";
                    input = new FileInputStream(new File(DataPath));
                    if (FtpUtil.uploadFile(ftpIp, ftpUserName, ftpPassword,
                            Integer.valueOf(ftpPort), datFtpPath, filename, input)) {
                        log.info("柜员信息表就绪文件推送成功!!!");
                    }
                }
            }
        } catch (Exception e) {
            // TODO 自动生成的 catch 块
            log.info(tableName+"数据推送过程异常：" + e.toString());
            e.printStackTrace();
        } finally {
            if (executor != null) {
                executor.closeConnection();
            }
        }
    }

    /**
     * 跟据导出生成对应ctl文件
     * @param path
     * @return
     */
    public static String createCtlFile(String path, String day, String count,String SysNum) {
        FileOutputStream fileOutputStream = null;
        File dayZhanghData = null;
        File dayZhanghCtl = null;
        String ctlPath = null;
        if (path != null) {
            ctlPath = path.substring(0, path.lastIndexOf(".")) + ".ctl";
        }
        ;
        try {
            dayZhanghData = new File(path);//
            if (dayZhanghData.exists()) {
                dayZhanghCtl = new File(ctlPath);
                if (dayZhanghCtl.exists()) {
                    log.info(ctlPath + "已存在!!!删除！！！");
                    if (dayZhanghCtl.delete()) {
                        log.info(ctlPath + "删除成功！！！");
                    }
                }
                if (dayZhanghCtl.createNewFile()) {
                    fileOutputStream = new FileOutputStream(dayZhanghCtl);
                    String zhanghCtlInfo = "";
                    zhanghCtlInfo += SysNum + (char) 0x1b;
                    // 全量
                    zhanghCtlInfo += "1" + (char) 0x1b;
                    // 日期
                    zhanghCtlInfo += day + (char) 0x1b;
                    // 文件名
                    zhanghCtlInfo += path.substring(path.lastIndexOf("/") + 1) + (char) 0x1b;
                    // 数量
                    zhanghCtlInfo += count + (char) 0x1b;
                    // 文件大小
                    zhanghCtlInfo += dayZhanghData.length() + (char) 0x1b;
                    // 文件生成时间戳
                    zhanghCtlInfo += new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                            .format(new Date(dayZhanghData.lastModified()));
                    fileOutputStream.write(zhanghCtlInfo.getBytes());
                } else {
                    log.info("创建ctl失败!!!");
                    ctlPath = null;
                }
            } else {
                log.info("生成ctl文件失败，" + path + "未找到!!!");
                ctlPath = null;
            }
        } catch (FileNotFoundException e) {
            log.info("生成ctl文件失败，" + ctlPath + "未找到!!!");
            ctlPath = null;
        } catch (IOException e) {
            // TODO 自动生成的 catch 块
            log.info("信息写入失败");
            ctlPath = null;
        } finally {
            try {
                dayZhanghData = null;
                dayZhanghCtl = null;
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
            } catch (Exception e2) {
                // TODO: handle exception
            }
        }
        return ctlPath;
    }

    /**
     * 获取数据条数
     * @param sql
     * @return
     */
    public static String getDataCount(String sql) {
        String count = "";
        PreparedStatement ps = null;
        ResultSet rs = null;
        Connection con = null;
        try {
            con = OConnManagerment.getDB2connction();
            ps = con.prepareStatement(sql);
            rs = ps.executeQuery();
            if (rs.next()) {
                count = rs.getString(1);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info("获取导出数据条数时发生异常:|" + e);
        } finally {
            OConnManagerment.close(rs, ps, con);
        }
        return count;
    }

    /**
     * 修改推送模式为增量
     * @param tid 任务id
     * @return
     */
    private void setTaskToIncrements(String tid){
        DataExportDTO dataExportId = dataExportDao.getDataExportId(tid);
        dataExportId.setTableIsIncrements("1");
        dataExportDao.updateDataExport(dataExportId);
    }


    private void createLinuxPath(String dataExportPathpar,RemoteShellExecutor executor){
        try {
            // 使用命令检查远程路径是否存在
            String checkPathCommand = "if [ ! -d " + dataExportPathpar + " ]; then echo 'Not Found'; fi";
            int exitCode = executor.sh(checkPathCommand);
            // 如果路径不存在，创建它
            if (true) {
                String createPathCommand = "mkdir -p " + dataExportPathpar;
                int createExitCode = executor.sh(createPathCommand);
                if (createExitCode == 0) {
                    log.info("成功创建远程路径：" + dataExportPathpar);
                } else {
                    log.info("无法创建远程路径：" + dataExportPathpar);
                }
            } else {
                log.info("远程路径已存在：" + dataExportPathpar);
            }
        } catch (Exception e) {
            log.info("判断远程文件路径错误！");
        }
    }
}
